﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;

using NuMetaheuristics.Genotypes;
using NuMetaheuristics.Operators.Vector;
using NuMetaheuristics.Operators.Value;

namespace NuMetaheuristics.Contexts.Vector.Double
{
    [DataContract(Namespace = "http://numetaheuristics.codeplex.com/schemas")]
    abstract public class DoubleVectorContext : IContext<DoubleVectorGenotype>
    {
        [DataMember]
        protected int _length;

        [DataMember]
        protected IUnaryOperator<DoubleVectorGenotype> _initializer;

        [DataMember]
        private DoubleVectorBounding _bounding;

        public DoubleVectorContext()
        {
        }

        public DoubleVectorContext(int length, double min, double max)
        {
            _length = length;
            _initializer = new DoubleVectorInitializer(new DoubleRandomInitializer(min, max));
            _bounding = new DoubleVectorBounding(min, max);
        }

        public DoubleVectorGenotype Produce(bool initialize, bool makeValid, bool evaluate)
        {
            var candidate = new DoubleVectorGenotype(_length);

            if (initialize)
            {
                Initialize(ref candidate);
            }

            if (makeValid && !IsValid(candidate))
            {
                MakeValid(ref candidate);
            }

            if (evaluate)
            {
                Evaluate(ref candidate);
            }

            return candidate;
        }

        public void Initialize(ref DoubleVectorGenotype candidate)
        {
            _initializer.Operate(ref candidate);
        }

        abstract public void Evaluate(ref DoubleVectorGenotype candidate);

        public bool IsValid(DoubleVectorGenotype candidate)
        {
            return _bounding.IsBounded(candidate);
        }

        public void MakeValid(ref DoubleVectorGenotype candidate)
        {
            if (IsValid(candidate))
                return;

            _bounding.Operate(ref candidate);
        }
    }
}
